package com.jlpay.open.jlpay.sdk.java.http;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jlpay.open.jlpay.sdk.java.enums.DigestAlgorithmType;
import com.jlpay.open.jlpay.sdk.java.exception.SignVerifyException;
import com.jlpay.open.jlpay.sdk.java.sign.SignVerifierManager;
import com.jlpay.open.jlpay.sdk.java.utils.NonceUtils;
import com.jlpay.open.jlpay.sdk.java.utils.json.JsonUtils;

import java.time.Instant;
import java.util.Map;
import java.util.Objects;

/**
 * @author zhaomeixia
 * @since 2024/2/20
 */
public abstract class AbstractHttpClient implements HttpClient {

    private final SignVerifierManager signVerifierManager;

    protected AbstractHttpClient(SignVerifierManager signVerifierManager) {
        this.signVerifierManager = signVerifierManager;
    }

    @Override
    public <T> T post(HttpRequest httpRequest, Class<T> responseClass) {
        HttpResponse httpResponse = post(httpRequest);
        return JsonUtils.parseObject(httpResponse.getBody(), responseClass);
    }

    @Override
    public HttpResponse post(HttpRequest httpRequest) {
        //请求签名
        HttpRequest signRequest = requestSign(httpRequest, HttpMethod.POST);

        HttpResponse httpResponse = sendPost(signRequest);
        if (!signVerifierManager.verify(signRequest, httpResponse)) {
            throw new SignVerifyException("verify signature failed，response: " + httpResponse);
        }
        return httpResponse;
    }

    @Override
    public HttpResponse get(HttpRequest httpRequest) {
        //请求签名
        HttpRequest signRequest = requestSign(httpRequest, HttpMethod.GET);

        HttpResponse httpResponse = sendGet(signRequest);
        if (!signVerifierManager.verify(signRequest, httpResponse)) {
            throw new SignVerifyException("verify signature failed，response: " + httpResponse);
        }
        return httpResponse;
    }

    @Override
    public <T> T postForm(MultipartHttpRequest request, Class<T> responseClass) {
        ObjectNode meta = request.getMeta();
        String digest = DigestAlgorithmType.getDigestByType(
                DigestAlgorithmType.getType(meta.get("alg").textValue()), request.getFile());
        Objects.requireNonNull(digest, "digest calculate failed");
        meta.put("abstract", digest);
        request.setMeta(meta);

        MultipartHttpRequest postRequest = request.toBuilder()
                .method(HttpMethod.POST)
                .addHeader(JlpayHttpHeaders.V5.TIMESTAMP, String.valueOf(Instant.now().getEpochSecond()))
                .addHeader(JlpayHttpHeaders.V5.NONCE, NonceUtils.createNonce(JlpayHttpHeaders.V5.NONCE_LENGTH))
                .addHeader(JlpayHttpHeaders.V5.SIGN_ALG, JlpayHttpHeaders.V5.ALG_SM3_WITH_SM2_WITH_DER)
                .build();
        String sign = signVerifierManager.sign(postRequest);
        postRequest.addHeader(JlpayHttpHeaders.V5.SIGN, sign);
        HttpResponse httpResponse = sendFromPost(postRequest);
        if (!signVerifierManager.verify(request, httpResponse)) {
            throw new SignVerifyException("verify signature failed，response: " + httpResponse);
        }
        return JsonUtils.parseObject(httpResponse.getBody(), responseClass);
    }

    private HttpRequest requestSign(HttpRequest httpRequest, HttpMethod method) {
        HttpRequest signRequest = httpRequest.toBuilder()
                .method(method)
                .addHeader(JlpayHttpHeaders.V5.TIMESTAMP, String.valueOf(Instant.now().getEpochSecond()))
                .addHeader(JlpayHttpHeaders.V5.NONCE, NonceUtils.createNonce(JlpayHttpHeaders.V5.NONCE_LENGTH))
                .addHeader(JlpayHttpHeaders.V5.SIGN_ALG, JlpayHttpHeaders.V5.ALG_SM3_WITH_SM2_WITH_DER)
                .build();
        String sign = signVerifierManager.sign(signRequest);
        signRequest.addHeader(JlpayHttpHeaders.V5.SIGN, sign);

        return signRequest;
    }

    /**
     * 获取请求ID
     *
     * @param headers 响应头
     */
    protected String getHeaderRequestId(Map<String, String> headers) {
        if (headers == null || headers.isEmpty()) {
            return null;
        }
        return headers.get("x-r-id");
    }

    /**
     * 发送 POST 请求实现
     *
     * @param httpRequest 请求参数
     * @return 响应参数
     */

    protected abstract HttpResponse sendPost(HttpRequest httpRequest);

    protected abstract HttpResponse sendGet(HttpRequest httpRequest);

    public abstract HttpResponse sendFromPost(MultipartHttpRequest httpRequest);
}
